/*
 * MIT License
 *
 * Copyright (c) 2023-present, tangli
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package tony.test.mybatis

import jakarta.annotation.Resource
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertNotNull
import org.junit.jupiter.api.Assertions.assertNull
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
import tony.core.utils.getLogger
import tony.test.mybatis.db.dao.UpsertTestDao
import tony.test.mybatis.db.po.UpsertTestEntity

/**
 * UpsertById 功能单元测试
 *
 * @author tangli
 * @date 2024/01/15 10:00
 */
@SpringBootTest(
    classes = [TestMyBatisApp::class],
    webEnvironment = SpringBootTest.WebEnvironment.NONE
)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class UpsertByIdTest {

    @Resource
    lateinit var upsertTestDao: UpsertTestDao

    @Resource
    lateinit var namedParameterJdbcTemplate: NamedParameterJdbcTemplate

    companion object {
        private val logger = getLogger()
    }

    @BeforeEach
    fun setUp() {
        // 清理测试数据
        namedParameterJdbcTemplate.update("DELETE FROM upsert_test", emptyMap<String, Any>())
    }

    @Test
    fun `测试插入新记录`() {
        // 准备测试数据
        val entity = UpsertTestEntity(
            id = 1L,
            businessKey = "test-key-001",
            name = "测试名称",
            description = "测试描述",
            remark = "测试备注",
            status = 1
        )

        // 执行 upsert
        val result = upsertTestDao.upsertById(entity)

        // 验证结果
        assertEquals(1, result, "应该插入1条记录")

        // 验证数据库中的记录
        val saved = upsertTestDao.selectById(1L)
        assertNotNull(saved, "记录应该存在")
        assertEquals("test-key-001", saved?.businessKey)
        assertEquals("测试名称", saved?.name)
        assertEquals("测试描述", saved?.description)
        assertEquals("测试备注", saved?.remark)
        assertEquals(1, saved?.status)
        assertNotNull(saved?.createTime, "创建时间应该自动填充")
        assertEquals("1", saved?.creatorId, "创建者ID应该自动填充")

        logger.info("插入测试完成: {}", saved)
    }

    @Test
    fun `测试更新已存在记录`() {
        val originalEntity = UpsertTestEntity(
            id = 2L,
            businessKey = "test-key-002",
            name = "原始名称",
            description = "原始描述",
            remark = "原始备注",
            status = 1
        )
        upsertTestDao.insert(originalEntity)

        // 准备更新数据
        val updateEntity = UpsertTestEntity(
            id = 2L,
            businessKey = "test-key-002-updated",
            name = "更新名称",
            description = "更新描述",
            remark = "更新备注",
            status = 2
        )

        // 执行 upsert
        val result = upsertTestDao.upsertById(updateEntity)

        // 验证结果
        assertEquals(2, result, "应该更新1条记录（MySQL ON DUPLICATE KEY UPDATE 返回2）")

        // 验证数据库中的记录
        val updated = upsertTestDao.selectById(2L)
        assertNotNull(updated, "记录应该存在")
        assertEquals("test-key-002-updated", updated?.businessKey)
        assertEquals("更新名称", updated?.name)
        assertEquals("更新描述", updated?.description)
        assertEquals("更新备注", updated?.remark)
        assertEquals(2, updated?.status)
        assertNotNull(updated?.updateTime, "更新时间应该自动填充")
        assertEquals("1", updated?.updatorId, "更新者ID应该自动填充")

        logger.info("更新测试完成: {}", updated)
    }

    @Test
    fun `测试字段策略 - 空值处理`() {
        // 准备测试数据，description 为空（insertStrategy = NOT_EMPTY）
        val entity = UpsertTestEntity(
            id = 3L,
            businessKey = "test-key-003",
            name = "测试名称",
            description = "", // 空字符串，应该被忽略
            remark = null, // null 值
            status = 1
        )

        // 执行 upsert
        val result = upsertTestDao.upsertById(entity)

        // 验证结果
        assertEquals(1, result, "应该插入1条记录")

        // 验证数据库中的记录
        val saved = upsertTestDao.selectById(3L)
        assertNotNull(saved, "记录应该存在")
        assertEquals("test-key-003", saved?.businessKey)
        assertEquals("测试名称", saved?.name)
        assertNull(saved?.description, "空字符串应该被忽略，保持为null")
        assertNull(saved?.remark, "null值应该保持为null")
        assertEquals(1, saved?.status)

        logger.info("字段策略测试完成: {}", saved)
    }

    @Test
    fun `测试更新时字段策略 - 空值处理`() {
        // 先插入一条记录
        val originalEntity = UpsertTestEntity(
            id = 4L,
            businessKey = "test-key-004",
            name = "原始名称",
            description = "原始描述",
            remark = "原始备注",
            status = 1
        )
        upsertTestDao.insert(originalEntity)

        // 准备更新数据，remark 为空（updateStrategy = NOT_EMPTY）
        val updateEntity = UpsertTestEntity(
            id = 4L,
            businessKey = "test-key-004-updated",
            name = "更新名称",
            description = "更新描述",
            remark = "", // 空字符串，应该被忽略
            status = 2
        )

        // 执行 upsert
        val result = upsertTestDao.upsertById(updateEntity)

        // 验证结果
        assertEquals(2, result, "应该更新1条记录")

        // 验证数据库中的记录
        val updated = upsertTestDao.selectById(4L)
        assertNotNull(updated, "记录应该存在")
        assertEquals("test-key-004-updated", updated?.businessKey)
        assertEquals("更新名称", updated?.name)
        assertEquals("更新描述", updated?.description)
        assertEquals("原始备注", updated?.remark, "空字符串应该被忽略，保持原值")
        assertEquals(2, updated?.status)

        logger.info("更新字段策略测试完成: {}", updated)
    }

}
